<style>
  .main-container {
    display: grid;
    grid-template-columns: minmax(150px, 50%) 1fr;
    height: 100vh;
    overflow: hidden;
  }

  .main-container > * {
    overflow-y: auto
  }

  .image-container { /* 相对定位的容器，用于包裹图片和canvas */
    position: relative;
    display: inline-block;
  }

  .image-container > canvas { /* 绝对定位的 canvas，使其精确叠放在图片上方 */
    position: absolute;
    top: 0;
    left: 0;
    z-index: 10; /* 确保 canvas 在图片上方 */
    pointer-events: none; /* 使 canvas 下方的图片可以点击 */
  }

  input[type="url"] {
    width: 100%;
    box-sizing: border-box;
  }
</style>
<div class="main-container">
  <form id="myForm" method="post">
    <button type="submit">submit</button>
    <button type="reset">reset</button>
    <br>
    <input type="hidden" name="tag" value="ocr">
    <label for="imageFile">file:</label>
    <input id="imageFile" name="imageFile" type="file" accept="image/*">
    <br>
    <label for="imageUrl">url:</label>
    <input id="imageUrl" name="imageUrl" type="url" list="imageUrlList">
    <datalist id="imageUrlList">
      <option label="general_ocr_001.png" value="https://paddle-model-ecology.bj.bcebos.com/paddlex/imgs/demo_image/general_ocr_001.png">
      <option label="general_ocr_002.png" value="https://paddle-model-ecology.bj.bcebos.com/paddlex/imgs/demo_image/general_ocr_002.png">
    </datalist>
    <br>
    <div class="image-container">
      <img src="#" alt="alt" style="max-width: 100%; max-height: 100%;">
      <canvas></canvas>
    </div>
  </form>
  <div id="result">result</div>
</div>
<script type="module">
  const form = document.getElementById('myForm');
  const resultDiv = document.getElementById('result');
  const image = document.querySelector('.image-container > img');
  const canvas = document.querySelector('.image-container > canvas');
  const dialog = document.querySelector('body > dialog');
  const ctx = canvas.getContext('2d');
  image.addEventListener('click', function (event) {
    clone = event.target.parentElement.cloneNode(true);
    // 使用 drawImage() 方法将旧 Canvas 的内容绘制到新 Canvas，参数: (源图像, 目标x, 目标y)
    clone.querySelector('canvas').getContext('2d').drawImage(canvas, 0, 0);
    dialog.appendChild(clone); // true 表示深克隆
    dialog.showModal();
  });
  image.addEventListener('load', function (event) {
    canvas.width = image.width; // 设置 canvas 的尺寸与图片相同
    canvas.height = image.height;
  })

  function draw(coordinate) {
    // canvas.width = image.width; // 设置 canvas 的尺寸与图片相同
    // canvas.height = image.height;
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除上次绘制内容
    ctx.lineWidth = 3; // 线条宽度
    ctx.strokeStyle = 'red'; // 线条颜色 blue
    ctx.beginPath();
    if (Array.isArray(coordinate[0])) { // 多边形边框(二维数组)
      ctx.moveTo(coordinate[0][0], coordinate[0][1]); // 移动到第一个点
      for (let i = 1; i < coordinate.length; i++) ctx.lineTo(coordinate[i][0], coordinate[i][1]); // 绘制到第 i 个点
      ctx.closePath(); // 连接起点和终点，形成闭合图形
      ctx.stroke(); // 绘制边框
    } else { // 矩形边框(一维数组)
      const [rectX, rectY, rectWidth, rectHeight] = coordinate;
      ctx.strokeRect(rectX, rectY, rectWidth, rectHeight);
    }
  }

  document.getElementById('imageFile').addEventListener('change', function (event) {
    const file = event.target.files[0];
    if (file && file.type.startsWith('image/')) { // 检查文件是否存在且为图片类型
      const reader = new FileReader(); // 使用 FileReader API 读取文件
      reader.onload = e => image.src = e.target.result; // 读取完成后，将结果(Data URL)赋值给 img 的 src
      reader.readAsDataURL(file); // 以 Data URL 的形式读取文件
    }
  });
  document.getElementById('imageUrl').addEventListener('input', event => image.src = event.target.value);
  form.addEventListener('submit', function (event) {
    resultDiv.innerText = 'Loading';
    event.preventDefault(); // 阻止表单的默认提交行为
    const formData = new FormData(form); // 创建 FormData 对象，会自动收集表单中的所有数据
    fetch('/upload/', {method: 'POST', body: formData})
      .then(response => {
        if (!response.ok) throw new Error('网络请求失败, 状态码: ' + response.status);
        return response.json();
      })
      .then(data => {
        data = data[0];
        // form.reset(); // 清空表单
        resultDiv.innerHTML = '';
        resultDiv.insertAdjacentHTML('afterbegin', '<h3>识别到的文本</h3>')
        const table = document.createElement('table');
        table.setAttribute('border', '1');
        resultDiv.appendChild(table);
        const thead = document.createElement('thead');
        table.appendChild(thead);
        const trHead = document.createElement('tr');
        thead.appendChild(trHead);
        ['文本识别结果', '置信度', '检测框', '边界框', '多边形框', '方向'].forEach(headerText => {
          const th = document.createElement('th');
          th.textContent = headerText;
          trHead.appendChild(th);
        });
        const tbody = document.createElement('tbody');
        table.appendChild(tbody);
        data.rec_texts.forEach((text, index) => {
          const tr = document.createElement('tr');
          tbody.appendChild(tr);
          const tdText = document.createElement('td');
          tdText.textContent = text;
          tr.appendChild(tdText);
          const tdScore = document.createElement('td');
          tdScore.textContent = data.rec_scores[index];
          tr.appendChild(tdScore);
          const tdPoly = document.createElement('td');
          tdPoly.textContent = JSON.stringify(data.rec_polys[index]);
          tdPoly.onclick = (event) => draw(JSON.parse(event.target.textContent));
          tr.appendChild(tdPoly);
          const tdBox = document.createElement('td');
          tdBox.textContent = JSON.stringify(data.rec_boxes[index]);
          tdBox.onclick = (event) => draw(JSON.parse(event.target.textContent));
          tr.appendChild(tdBox);
          const tdDtPoly = document.createElement('td');
          tdDtPoly.textContent = JSON.stringify(data.dt_polys[index]);
          tdDtPoly.onclick = (event) => draw(JSON.parse(event.target.textContent));
          tr.appendChild(tdDtPoly);
          const tdAngle = document.createElement('td');
          tdAngle.textContent = data.textline_orientation_angles[index];
          tr.appendChild(tdAngle);
        });
        resultDiv.insertAdjacentHTML('beforeend', `
        <p><strong>待预测图像的输入路径: </strong>${data.input_path}</p>
        <p><strong>如果输入是PDF文件，则表示当前是PDF的第几页，否则为 None: </strong>${data.page_index}</p>
        <h3>配置产线所需的模型参数</h3>
        <ul>
          <li>控制是否启用文档预处理子产线: ${data.model_settings.use_doc_preprocessor}</li>
          <li>控制是否启用文本行方向分类模块: ${data.model_settings.use_textline_orientation}</li>
        </ul>
        <h3>文档预处理子产线的输出结果。仅当use_doc_preprocessor=True时存在</h3>
        <ul>
          <li>图像预处理子产线接受的图像路径，当输入为numpy.ndarray时，保存为None: ${data.doc_preprocessor_res.input_path}</li>
          <li>预处理子产线的模型配置参数</li>
          <ul>
            <li>控制是否启用文档方向分类: ${data.doc_preprocessor_res.model_settings.use_doc_orientation_classify}</li>
            <li>控制是否启用文本图像矫正: ${data.doc_preprocessor_res.model_settings.use_doc_unwarping}</li>
          </ul>
          <li>文档方向分类的预测结果。启用时取值为[0,1,2,3]，分别对应[0°,90°,180°,270°]；未启用时为-1: ${data.doc_preprocessor_res.angle}</li>
        </ul>
        <h3>文本检测模块的配置参数</h3>
        <ul>
          <li>图像预处理时的边长限制值: ${data.text_det_params.limit_side_len}</li>
          <li>边长限制的处理方式: ${data.text_det_params.limit_type}</li>
          <li>文本像素分类的置信度阈值: ${data.text_det_params.thresh}</li>
          <li>文本检测框的置信度阈值: ${data.text_det_params.box_thresh}</li>
          <li>文本检测框的膨胀系数: ${data.text_det_params.unclip_ratio}</li>
          <li>文本检测的类型，当前固定为"general": ${data.text_det_params.text_type}</li>
        </ul>
        <p><strong>文本识别结果的过滤阈值: </strong>${data.text_rec_score_thresh}</p>
        <p><strong>return_word_box: </strong>${data.return_word_box}</p>
        <h3>preprocessed_img</h3>
        <img src="${data.preprocessed_img}" style="max-width: 100%; max-height: 100%;">
        <h3>ocr_res_img</h3>
        <img src="${data.ocr_res_img}" style="max-width: 100%; max-height: 100%;">
        `);
      })
      .catch(error => {
        resultDiv.textContent = JSON.stringify(error);
        resultDiv.style.color = 'red';
      });
  });
</script>